package com.bodu.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import com.bodu.core.entity.CommonEntity;
import com.bodu.core.entity.ParamReq;
import com.bodu.core.entity.enums.DelFlagEnum;
import com.bodu.system.entity.po.MenuPo;
import com.bodu.system.entity.request.MenuRequest;
import com.bodu.system.entity.vo.MenuMetaVo;
import com.bodu.system.entity.vo.MenuVo;
import com.bodu.system.enums.MenuTypeEnums;
import com.bodu.system.mapper.MenuMapper;
import com.bodu.system.mapper.MenuPermitMapper;
import com.bodu.system.service.MenuService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 菜单管理
 *
 * @author r.guo
 * @since 2019-05-25
 */
@Service("menuService")
public class MenuServiceImpl implements MenuService {

    /**
     * 最高编号
     */
    private final static Long ROOT_ID = -1L;

    @Resource
    private MenuMapper menuMapper;

    @Resource
    private MenuPermitMapper menuPermitMapper;

    /**
     * 是否是左边菜单数据
     */
    private final static Integer IS_LEFT_MENU = 1;

    @Override
    public MenuVo getModel(Long id) {
        MenuPo menuPo = menuMapper.getModel(id);
        MenuVo menuVo = new MenuVo();
        BeanUtils.copyProperties(menuPo, menuVo);
        menuVo.setMenuTypeName(MenuTypeEnums.getStatusValues(menuPo.getMenuType()));
        return menuVo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long save(MenuRequest menuRequest) {
        menuRequest.setName(PinyinUtil.getPinyin(menuRequest.getTitle(), ""));
        // 目录
        if (ObjectUtil.equals(menuRequest.getMenuType(), 0)) {
            menuRequest.setPath(menuRequest.getName());
            if (ObjectUtil.isEmpty(menuRequest.getParentId())) {
                menuRequest.setParentId(-1L);
            }
        }
        menuMapper.save(menuRequest);
        return menuRequest.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long update(MenuRequest request) {
        request.setName(PinyinUtil.getPinyin(request.getTitle(), ""));
        if (ObjectUtil.isEmpty(request.getParentId())) {
            request.setParentId(-1L);
        }
         menuMapper.update(request);
        return request.getId();
    }

    @Override
    public List<MenuVo> listPage(ParamReq<MenuRequest> params) {
        List<MenuVo> menus = menuMapper.listPage(params);
        for (MenuVo menuPo : menus) {
            menuPo.setMenuTypeName(MenuTypeEnums.getStatusValues(menuPo.getMenuType()));
        }
        return menus;
    }

    @Override
    public Integer countPage(ParamReq<MenuRequest> params) {
        return menuMapper.countPage(params);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer updateDelFlagById(Long id, Integer delFlag) {
        return menuMapper.updateDelFlagById(id, delFlag);
    }

    @Override
    public List<MenuVo> loopList(MenuRequest menuRequest) {
        menuRequest.setDelFlag(DelFlagEnum.NO.getValue());
        ParamReq<MenuRequest> paramReq = new ParamReq<>();
        paramReq.setEntity(menuRequest);
        Integer total = countPage(paramReq);
        paramReq.setSize(total);
        // 得到所有的权限
        List<MenuVo> permits = listPage(paramReq);
        // 得到用户可以查询出来的菜单
        List<MenuPo> userMenus = menuPermitMapper.getUseMenuByAdminId(menuRequest.getUserId());
        // 用户的权限对应的菜单
        Set<Long> userMenuIds = userMenus.stream().map(CommonEntity::getId).collect(Collectors.toSet());
        Integer leftMenuFlag = menuRequest.getLeftMenuFlag();
        return getChildrenMenuVo(permits, ROOT_ID, userMenuIds, leftMenuFlag);
    }

    private MenuVo loopPermits(MenuVo rootPermit, List<MenuVo> permits, Integer leftMenuFlag, Set<Long> userMenuIds) {
        List<MenuVo> chidren = getChildrenMenuVo(permits, rootPermit.getId(), userMenuIds, leftMenuFlag);
        rootPermit.setChildren(chidren);
        return rootPermit;
    }

    private List<MenuVo> getChildrenMenuVo(List<MenuVo> permits, Long rootId, Set<Long> userMenuIds, Integer leftMenuFlag) {
        List<MenuVo> chidren = CollUtil.newArrayList();
        for (MenuPo p : permits) {
            if (ObjectUtil.isNotEmpty(p) && ObjectUtil.equals(p.getParentId(), rootId)) {
                MenuVo menuVo = new MenuVo();
                BeanUtils.copyProperties(p, menuVo);
                MenuMetaVo menuMetaVo = new MenuMetaVo();
                menuMetaVo.setTitle(menuVo.getTitle());
                menuMetaVo.setIcon(menuVo.getIcon());
                menuMetaVo.setParentId(menuVo.getParentId());
                menuVo.setMeta(menuMetaVo);

                boolean isLeftMenuEqual = ObjectUtil.equal(leftMenuFlag, IS_LEFT_MENU);
                boolean userMenuIdContains = userMenuIds.contains(p.getId());
                if ((isLeftMenuEqual && userMenuIdContains)) {
                    chidren.add(loopPermits(menuVo, permits, leftMenuFlag, userMenuIds));
                }

                if (ObjectUtil.notEqual(leftMenuFlag, IS_LEFT_MENU)) {
                    chidren.add(loopPermits(menuVo, permits, leftMenuFlag, userMenuIds));
                }
            }
        }
        if (ObjectUtil.isNotEmpty(chidren) && chidren.size() >= 1) {
            Collections.sort(chidren, Comparator.comparing(MenuPo::getMenuSort));
        }
        return chidren;
    }
}
